From ac30f8ce8c5fcea362443b23032d6e49da2b8d9e Mon Sep 17 00:00:00 2001 From: robertl Date: Mon, 24 Nov 2003 15:42:05 +0000 Subject: [PATCH] Add Geoniche. From Rick Richardson. --- Makefile | 2 +- geoniche.c | 514 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vecs.c | 7 + 3 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 geoniche.c diff --git a/Makefile b/Makefile index 0183705d4..d0bfa5132 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o \ gpsutil.o pcx.o cetus.o copilot.o gpspilot.o magnav.o \ psp.o holux.o garmin.o tmpro.o tpg.o \ xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \ - gpilots.o saroute.o navicache.o psitrex.o + gpilots.o saroute.o navicache.o psitrex.o geoniche.o FILTERS=position.o duplicate.o arcdist.o polygon.o diff --git a/geoniche.c b/geoniche.c new file mode 100644 index 000000000..5437f6e68 --- /dev/null +++ b/geoniche.c @@ -0,0 +1,514 @@ +/* + Read and write GeoNiche files. + + Copyright (C) 2003 Rick Richardson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "coldsync/palm.h" +#include "coldsync/pdb.h" + +#define MYNAME "Geoniche" +#define MYTYPE 0x50454e44 /* PEND */ +#define MYCREATOR 0x47656f4e /* GeoN */ + +static FILE *FileIn; +static FILE *FileOut; +static const char *FilenameOut; +static struct pdb *PdbOut; + +static char Rec0Magic[] = "68000NV4Q2"; + +/* + * Conversions between gc.com ID's and GID's + */ +static char GcSet[] = "0123456789ABCDEFGHJKMNPQRTVWXYZ"; +static int GcOffset = 16 * 31 * 31 * 31 - 65536; + +static int +gid2id(char *gid) +{ + char *p; + int i, val; + + if (strncmp(gid, "GC", 2) != 0) + return -1; + if (strlen(gid) != 6) + return -1; + gid += 2; + + if (strcmp(gid, "G000") < 0) + return strtol(gid, NULL, 16); + + for (val = i = 0; i < 4; ++i) + { + val *= 31; + p = strchr(GcSet, gid[i]); + if (!p) return -1; + val += p - GcSet; + } + return val - GcOffset; +} + +static void +id2gid(char gid[6+1], int id) +{ + gid[0] = 0; + if (id < 0) + return; + else if (id < 65536) + snprintf(gid, 6+1, "GC%04X", id); + else + { + int i; + + id += GcOffset; + gid[0] = 'G'; + gid[1] = 'C'; + for (i = 5; i >= 2; --i) { + gid[i] = GcSet[id%31]; + id /= 31; + } + gid[6] = 0; + if (id) + gid[0] = 0; + } + return; +} + +static void +rd_init(const char *fname) +{ + FileIn = fopen(fname, "rb"); + if (FileIn == NULL) + fatal(MYNAME ": Cannot open %s for reading\n", fname); +} + +static void +rd_deinit(void) +{ + fclose(FileIn); +} + +static void +wr_init(const char *fname) +{ + FileOut = fopen(fname, "wb"); + FilenameOut = fname; + if (FileOut == NULL) + fatal(MYNAME ": Cannot open %s for writing\n", fname); +} + +static void +wr_deinit(void) +{ + fclose(FileOut); +} + +static char * +field(char **pp, int *lenp) +{ + int len = *lenp; + char *p = *pp; + char *dp, *dbuf; + int state = 0; + + if (len == 0 || *p == 0) + return NULL; + + dbuf = dp = xmalloc(len); + while (len) + { + char ch; + + ch = *p++; + --len; + if (ch == 0 || len == 0) + break; + switch (state) + { + case 0: + if (ch == '\\') + state = 1; + else if (ch == ',') + goto eof; + else + *dp++ = ch; + break; + default: + *dp++ = ch; + state = 0; + break; + } + } +eof: + *dp++ = 0; + dbuf = xrealloc(dbuf, dp - dbuf); + /* fprintf(stderr, "<%.8s> dbuf=%x, len=%d\n", *pp, dbuf, len); */ + *pp = p; + *lenp = len; + return dbuf; +} + +static void +data_read(void) +{ + struct pdb *pdb; + struct pdb_record *pdb_rec; + + if (NULL == (pdb = pdb_Read(fileno(FileIn)))) + fatal(MYNAME ": pdb_Read failed\n"); + + if ((pdb->creator != MYCREATOR) || (pdb->type != MYTYPE)) + fatal(MYNAME ": Not a GeoNiche file.\n"); + + /* Process record 0 */ + pdb_rec = pdb->rec_index.rec; + if (strcmp(pdb_rec->data, Rec0Magic)) + fatal(MYNAME ": Bad record 0, not a GeoNiche file.\n"); + pdb_rec = pdb_rec->next; + + /* Process the rest of the records */ + for (; pdb_rec; pdb_rec = pdb_rec->next) + { + waypoint *wpt; + char *vdata; + int vlen; + char *p; + + int id; + int route_id; + char *title; + char *category; + double lat, lon, alt; + char *datestr, *timestr; + int icon; + char *notes; + char gid[6+1]; + struct tm tm; + + wpt = xcalloc(sizeof(*wpt), 1); + if (!wpt) + fatal(MYNAME ": Couldn't allocate waypoint.\n"); + vdata = (char *) pdb_rec->data; + vlen = pdb_rec->data_len; + + /* Field 1: Target */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 1.\n"); + if (strcmp(p, "Target")) + fatal(MYNAME ": Can only handle Target records.\n"); + xfree(p); + + /* Field 2: Import ID number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 2.\n"); + id = atoi(p); + xfree(p); + + /* Field 3: Title */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 3.\n"); + title = p; + + /* Field 4: Route ID number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 4.\n"); + route_id = atoi(p); + xfree(p); + + /* Field 5: Category */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 5.\n"); + category = p; + + /* Field 6: Latitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 6.\n"); + lat = atof(p); + xfree(p); + + /* Field 7: Longitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 7.\n"); + lon = atof(p); + xfree(p); + + /* Field 8: Altitude */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 8.\n"); + alt = atof(p); + xfree(p); + + /* Field 9: Creation date */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 9.\n"); + datestr = p; + + /* Field 10: Creation time */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 10.\n"); + timestr = p; + + /* Field 11: Visited date */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 11.\n"); + xfree(p); + + /* Field 12: Visited time */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 12.\n"); + xfree(p); + + /* Field 13: Icon color (R G B) */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 13.\n"); + xfree(p); + + /* Field 14: icon number */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 14.\n"); + icon = atoi(p); + xfree(p); + + /* Field 15: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 15.\n"); + xfree(p); + + /* Field 16: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 16.\n"); + xfree(p); + + /* Field 17: unused */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 17.\n"); + xfree(p); + + /* Field 18: Notes */ + p = field(&vdata, &vlen); + if (!p) fatal(MYNAME ": Premature EOD processing field 18.\n"); + notes = p; + + sscanf(datestr, "%d/%d/%d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year); + tm.tm_mon -= 1; + tm.tm_year -= 1900; + sscanf(timestr, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + wpt->creation_time = mktime(&tm); + xfree(datestr); + xfree(timestr); + + id2gid(gid, id); + wpt->latitude = lat; + wpt->longitude = lon; + wpt->altitude = alt; + wpt->icon_descr = category; + + if (gid[0]) + { + wpt->shortname = strdup(gid); + wpt->description = title; + wpt->notes = notes; + } + else + { + wpt->shortname = strdup(title); + wpt->description = title; + wpt->notes = notes; + } + + waypt_add(wpt); + } + free_pdb(pdb); +} + +static char * +enscape(char *s) +{ + char *buf, *d; + + if (!s) + { + d = xmalloc(1); + *d = 0; + return d; + } + buf = d = xmalloc(strlen(s) * 2 + 1); + for (; *s; ++s) + { + if (*s == '\\' || *s == ',') + *d++ = '\\'; + *d++ = *s; + } + + *d = 0; + return buf; +} + +/* + * Attempt to map an icon description into a GeoNiche icon number + */ +static int +wpt2icon(const waypoint *wpt) +{ + const char *desc = wpt->icon_descr; + + if (!desc) return 0; + else if (strstr(desc, "reg")) return 43; + else if (strstr(desc, "trad")) return 43; + else if (strstr(desc, "multi")) return 44; + else if (strstr(desc, "offset")) return 44; + else if (strstr(desc, "virt")) return 45; + else if (strstr(desc, "loca")) return 45; + else if (strstr(desc, "event")) return 46; + else if (strstr(desc, "lett")) return 47; + else if (strstr(desc, "hyb")) return 47; + else if (strstr(desc, "unk")) return 48; + else if (strstr(desc, "cam")) return 49; + else return 0; +} + +static void +copilot_writewpt(const waypoint *wpt) +{ + static int ct = 0; + struct pdb_record *opdb_rec; + int vlen; + static int vsize = 4096; + char *vdata; + char *title; + struct tm tm; + char datestr[10+1]; + char timestr[8+1]; + char *notes; + int id; + + if (ct == 0) + { + opdb_rec = new_Record (0, 0, ct++, sizeof(Rec0Magic), Rec0Magic); + if (opdb_rec == NULL) + fatal(MYNAME ": libpdb couldn't create record\n"); + if (pdb_AppendRecord(PdbOut, opdb_rec)) + fatal(MYNAME ": libpdb couldn't append record\n"); + } + + if (wpt->description[0]) + title = enscape(wpt->description); + else + title = enscape(wpt->shortname); + + id = gid2id(wpt->shortname); + if (id < 0) + id = ct; + + tm = *localtime(&wpt->creation_time); + strftime(datestr, sizeof(datestr), "%m/%d/%Y", &tm); + strftime(timestr, sizeof(timestr), "%H:%M:%S", &tm); + + /* Notes field MUST have soemthing in it */ + if (!wpt->notes || wpt->notes[0] == 0) + notes = strdup(title); + else + notes = enscape(wpt->notes); + + vdata = (char *) xmalloc(vsize); + if (vdata == NULL) + fatal(MYNAME ": libpdb couldn't get record memory\n"); + + for (;;) + { + vlen = snprintf(vdata, vsize, + "Target,%d,%s,,%s,%f,%f,%f,%s,%s,,,,%d,,,,%s" + , id + , title + /* route ID */ + , "Cache" /*wpt->icon_descr*/ + , wpt->latitude + , wpt->longitude + , wpt->altitude + , datestr + , timestr + /* visited date */ + /* visited time */ + /* icon color R G B */ + , wpt2icon(wpt) + /* unused1 */ + /* unused2 */ + /* unused3 */ + , notes + ); + + if (vlen > -1 && vlen < vsize) + break; + + /* try again with more space. */ + if (vlen > -1) + vsize = vlen + 1; + else + vsize *= 2; + vdata = (char *) xrealloc(vdata, vsize); + if (vdata == NULL) + fatal(MYNAME ": libpdb couldn't get record memory\n"); + } + + opdb_rec = new_Record (0, 0, ct++, vlen+1, vdata); + + if (opdb_rec == NULL) + fatal(MYNAME ": libpdb couldn't create record\n"); + if (pdb_AppendRecord(PdbOut, opdb_rec)) + fatal(MYNAME ": libpdb couldn't append record\n"); + + xfree(notes); + xfree(title); + xfree(vdata); +} + +static void +data_write(void) +{ + if (NULL == (PdbOut = new_pdb())) + fatal (MYNAME ": new_pdb failed\n"); + + strncpy(PdbOut->name, FilenameOut, PDB_DBNAMELEN); + PdbOut->name[PDB_DBNAMELEN-1] = 0; + PdbOut->attributes = PDB_ATTR_BACKUP; + PdbOut->ctime = PdbOut->mtime = time(NULL) + (49*365 + 17*366) * (60*60*24); + PdbOut->type = MYTYPE; + PdbOut->creator = MYCREATOR; + PdbOut->version = 0; + PdbOut->modnum = 1; + + waypt_disp_all(copilot_writewpt); + + pdb_Write(PdbOut, fileno(FileOut)); + + free_pdb(PdbOut); +} + + +ff_vecs_t geoniche_vecs = +{ + rd_init, + wr_init, + rd_deinit, + wr_deinit, + data_read, + data_write, + NULL +}; diff --git a/vecs.c b/vecs.c index 7de8df7d2..108d72f5d 100644 --- a/vecs.c +++ b/vecs.c @@ -55,6 +55,7 @@ extern ff_vecs_t gpilots_vecs; extern ff_vecs_t saroute_vecs; extern ff_vecs_t navicache_vecs; extern ff_vecs_t psit_vecs; /* MRCB */ +extern ff_vecs_t geoniche_vecs; static vecs_t vec_list[] = { @@ -209,6 +210,12 @@ vecs_t vec_list[] = { "KuDaTa PsiTrex text", NULL }, + { + &geoniche_vecs, + "geoniche", + "GeoNiche .pdb", + NULL + }, { NULL, NULL, -- 2.30.2